package com.cal.utms.entity;

import java.io.Serializable;

import javax.persistence.*;

import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;

import com.cal.utms.logAudit.AuditLogInt;
import com.cal.utms.util.ValueConvert;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * The persistent class for the instrument database table.
 * 
 */
@Entity
@Table(name = "instrument")
@NamedQuery(name = "Instrument.findAll", query = "SELECT i FROM Instrument i")
public class Instrument implements Serializable, AuditLogInt {
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(unique = true, nullable = false)
	private int id;

	@Column(name = "BENCH_MARK", length = 45)
	private String benchMark;

	@Column(precision = 10, scale = 4)
	private BigDecimal ceiling;

	@Column(name = "COUPON_FREQ")
	private Integer couponFreq;

	@Column(name = "COUPON_RATE", precision = 10, scale = 4)
	private BigDecimal couponRate;

	@Column(name = "DAY_BASIS", length = 45)
	private String dayBasis;

	@Column(precision = 10, scale = 4)
	private BigDecimal floor;

	@Column(name = "INSTRUMENT_CODE", length = 45)
	private String instrumentCode;

	@Column(name = "LABEL", length = 30)
	private String label;

	@Column(name = "INSTRUMENT_VALUE", precision = 10, scale = 4)
	private BigDecimal instrumentValue;

	@Column(name = "VALUE_OUT", precision = 10, scale = 4)
	private BigDecimal valueOut;

	@Temporal(TemporalType.DATE)
	@Column(name = "ISSUE_DATE")
	private Date issueDate;

	@Temporal(TemporalType.DATE)
	@Column(name = "MATURITY_DATE")
	private Date maturityDate;

	@Column(name = "MIN_DENOMINAL", precision = 10, scale = 4)
	private BigDecimal minDenominal;

	@Temporal(TemporalType.DATE)
	@Column(name = "RESET_DATE")
	private Date resetDate;

	@Column(name = "RESET_PERIOD")
	private Integer resetPeriod;

	@Column(length = 12)
	private String status;

	// uni-directional many-to-one association to Deal
	@ManyToOne
	@JoinColumn(name = "LAST_DEAL")
	private Deal lastDeal;

	// uni-directional many-to-one association to Issure
	@ManyToOne
	@JoinColumn(name = "ISSUER_ID")
	private Issuer issuer;

	// uni-directional many-to-one association to InstrumentType
	@ManyToOne
	@JoinColumn(name = "INSTRUMENT_TYPE_ID")
	private InstrumentType instrumentType;

	// bi-directional many-to-one association to InstrumentCouponDate
	@OneToMany(mappedBy = "instrument", fetch = FetchType.EAGER)
	@Fetch(value = FetchMode.SUBSELECT)
	private List<InstrumentCouponDate> instrumentCouponDates;

	// bi-directional many-to-one association to InstrumentFloatingRate
	@OneToMany(mappedBy = "instrument", fetch = FetchType.EAGER)
	@Fetch(value = FetchMode.SUBSELECT)
	private List<InstrumentFloatingRate> instrumentFloatingRates;

	public Instrument() {
	}

	public int getId() {
		return this.id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getBenchMark() {
		return this.benchMark;
	}

	public void setBenchMark(String benchMark) {
		this.benchMark = benchMark;
	}

	public BigDecimal getCeiling() {
		return this.ceiling;
	}

	public void setCeiling(BigDecimal ceiling) {
		this.ceiling = ceiling;
	}

	public Integer getCouponFreq() {
		return this.couponFreq;
	}

	public void setCouponFreq(Integer couponFreq) {
		this.couponFreq = couponFreq;
	}

	public BigDecimal getCouponRate() {
		return this.couponRate;
	}

	public void setCouponRate(BigDecimal couponRate) {
		this.couponRate = couponRate;
	}

	public String getDayBasis() {
		return this.dayBasis;
	}

	public void setDayBasis(String dayBasis) {
		this.dayBasis = dayBasis;
	}

	public BigDecimal getFloor() {
		return this.floor;
	}

	public void setFloor(BigDecimal floor) {
		this.floor = floor;
	}

	public String getInstrumentCode() {
		return this.instrumentCode;
	}

	public String getLabel() {
		return label;
	}

	public void setLabel(String label) {
		this.label = label;
	}

	public void setInstrumentCode(String instrumentCode) {
		this.instrumentCode = instrumentCode;
	}

	public BigDecimal getInstrumentValue() {
		return this.instrumentValue;
	}

	public void setInstrumentValue(BigDecimal instrumentValue) {
		this.instrumentValue = instrumentValue;
	}

	public BigDecimal getValueOut() {
		return valueOut;
	}

	public void setValueOut(BigDecimal valueOut) {
		this.valueOut = valueOut;
	}

	public static long getSerialversionuid() {
		return serialVersionUID;
	}

	public Date getIssueDate() {
		return this.issueDate;
	}

	public void setIssueDate(Date issueDate) {
		this.issueDate = issueDate;
	}

	public Date getMaturityDate() {
		return this.maturityDate;
	}

	public void setMaturityDate(Date maturityDate) {
		this.maturityDate = maturityDate;
	}

	public BigDecimal getMinDenominal() {
		return this.minDenominal;
	}

	public void setMinDenominal(BigDecimal minDenominal) {
		this.minDenominal = minDenominal;
	}

	public Date getResetDate() {
		return this.resetDate;
	}

	public void setResetDate(Date resetDate) {
		this.resetDate = resetDate;
	}

	public Integer getResetPeriod() {
		return this.resetPeriod;
	}

	public void setResetPeriod(Integer resetPeriod) {
		this.resetPeriod = resetPeriod;
	}

	public String getStatus() {
		return this.status;
	}

	public void setStatus(String status) {
		this.status = status;
	}

	public Deal getLastDeal() {
		return this.lastDeal;
	}

	public void setLastDeal(Deal deal) {
		this.lastDeal = deal;
	}

	public Issuer getIssuer() {
		return this.issuer;
	}

	public void setIssuer(Issuer issuer) {
		this.issuer = issuer;
	}

	public InstrumentType getInstrumentType() {
		return this.instrumentType;
	}

	public void setInstrumentType(InstrumentType instrumentType) {
		this.instrumentType = instrumentType;
	}

	public List<InstrumentCouponDate> getInstrumentCouponDates() {
		return this.instrumentCouponDates;
	}

	public void setInstrumentCouponDates(List<InstrumentCouponDate> instrumentCouponDates) {
		this.instrumentCouponDates = instrumentCouponDates;
	}

	public InstrumentCouponDate addInstrumentCouponDate(InstrumentCouponDate instrumentCouponDate) {
		getInstrumentCouponDates().add(instrumentCouponDate);
		instrumentCouponDate.setInstrument(this);

		return instrumentCouponDate;
	}

	public InstrumentCouponDate removeInstrumentCouponDate(InstrumentCouponDate instrumentCouponDate) {
		getInstrumentCouponDates().remove(instrumentCouponDate);
		instrumentCouponDate.setInstrument(null);

		return instrumentCouponDate;
	}

	public List<InstrumentFloatingRate> getInstrumentFloatingRates() {
		return this.instrumentFloatingRates;
	}

	public void setInstrumentFloatingRates(List<InstrumentFloatingRate> instrumentFloatingRates) {
		this.instrumentFloatingRates = instrumentFloatingRates;
	}

	public InstrumentFloatingRate addInstrumentFloatingRate(InstrumentFloatingRate instrumentFloatingRate) {
		getInstrumentFloatingRates().add(instrumentFloatingRate);
		instrumentFloatingRate.setInstrument(this);

		return instrumentFloatingRate;
	}

	public InstrumentFloatingRate removeInstrumentFloatingRate(InstrumentFloatingRate instrumentFloatingRate) {
		getInstrumentFloatingRates().remove(instrumentFloatingRate);
		instrumentFloatingRate.setInstrument(null);

		return instrumentFloatingRate;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Instrument) {
			Instrument ins = (Instrument) obj;

			if (this.benchMark != null && !this.benchMark.equals(ins.benchMark)) {
				System.out.println("benchMark:" + this.benchMark + ":" + ins.benchMark);
				return false;
			}

			if (this.ceiling == null) {
				if (ins.ceiling != null) {
					System.out.println("ceiling:" + this.ceiling + ":" + ins.ceiling);
					return false;
				}
			} else if (ins.ceiling == null) {
				if (this.ceiling != null) {
					System.out.println("ceiling:" + this.ceiling + ":" + ins.ceiling);
					return false;
				}
			} else if (this.ceiling.doubleValue() != ins.ceiling.doubleValue()) {
				System.out.println("ceiling:" + this.ceiling + ":" + ins.ceiling);
				return false;
			}

			if (this.couponFreq == null) {
				if (ins.couponFreq != null) {
					System.out.println("couponFreq:" + this.couponFreq + ":" + ins.couponFreq);
					return false;
				}
			} else if (ins.couponFreq == null) {
				if (this.couponFreq != null) {
					System.out.println("couponFreq:" + this.couponFreq + ":" + ins.couponFreq);
					return false;
				}
			} else if (this.couponFreq.doubleValue() != ins.couponFreq.doubleValue()) {
				System.out.println("couponFreq:" + this.couponFreq + ":" + ins.couponFreq);
				return false;
			}

			if (this.couponRate == null) {
				if (ins.couponRate != null) {
					System.out.println("couponRate:" + this.couponRate + ":" + ins.couponRate);
					return false;
				}
			} else if (ins.couponRate == null) {
				if (this.couponRate != null) {
					System.out.println("couponRate:" + this.couponRate + ":" + ins.couponRate);
					return false;
				}
			} else if (this.couponRate.doubleValue() != ins.couponRate.doubleValue()) {
				System.out.println("couponRate:" + this.couponRate + ":" + ins.couponRate);
				return false;
			}

			if (this.floor == null) {
				if (ins.floor != null) {
					System.out.println("floor:" + this.floor + ":" + ins.floor);
					return false;
				}
			} else if (ins.floor == null) {
				if (this.floor != null) {
					System.out.println("floor:" + this.floor + ":" + ins.floor);
					return false;
				}
			} else if (this.floor.doubleValue() != ins.floor.doubleValue()) {
				System.out.println("floor:" + this.floor + ":" + ins.floor);
				return false;
			}

			if (this.instrumentCouponDates != null) {
				if (ins.instrumentCouponDates == null) {
					System.out.println("coupon dates:" + this.instrumentCouponDates + ":null" + ins.floor);
					return false;
				} else {

					List<Date> one = new ArrayList<Date>();
					List<Date> two = new ArrayList<Date>();
					for (InstrumentCouponDate icd : this.instrumentCouponDates) {
						one.add(icd.getCouponDate());
					}
					for (InstrumentCouponDate icd : ins.instrumentCouponDates) {
						two.add(icd.getCouponDate());
					}

					Collections.sort(one);
					Collections.sort(two);

					if (!one.equals(two)) {
						System.out.println("Coupon Dates Mismatch!");
						for (Date date : one) {
							System.out.println(date);
						}
						for (Date date : two) {
							System.out.println(date);
						}
						return false;
					}

				}
			}

			if (!this.issuer.getCode().equals(ins.issuer.getCode())) {
				System.out.println("issuer:" + this.issuer.getCode() + ":" + ins.issuer.getCode());
				return false;
			}

			if (this.minDenominal == null) {
				if (ins.minDenominal != null) {
					System.out.println("minDenominal:" + this.minDenominal + ":" + ins.minDenominal);
					return false;
				}
			} else if (ins.minDenominal == null) {
				if (this.minDenominal != null) {
					System.out.println("minDenominal:" + this.minDenominal + ":" + ins.minDenominal);
					return false;
				}
			} else if (this.minDenominal.doubleValue() != ins.minDenominal.doubleValue()) {
				System.out.println("minDenominal:" + this.minDenominal + ":" + ins.minDenominal);
				return false;
			}

			if (this.resetDate != null && !this.resetDate.equals(ins.resetDate)) {
				System.out.println("resetDate:" + this.resetDate + ":" + ins.resetDate);
				return false;
			}

			if (this.resetPeriod == null) {
				if (ins.resetPeriod != null) {
					System.out.println("resetPeriod:" + this.resetPeriod + ":" + ins.resetPeriod);
					return false;
				}
			} else if (ins.resetPeriod == null) {
				if (this.resetPeriod != null) {
					System.out.println("resetPeriod:" + this.resetPeriod + ":" + ins.resetPeriod);
					return false;
				}
			} else if (this.resetPeriod.doubleValue() != ins.resetPeriod.doubleValue()) {
				System.out.println("resetPeriod:" + this.resetPeriod + ":" + ins.resetPeriod);
				return false;
			}

			return true;

		} else {
			// System.out.println("B is not and Instrument!");
			return false;
		}
	}

	@Transient
	@Override
	public Long getLogId() {
		return ValueConvert.toLong(this.id);
	}

	@Transient
	@Override
	public String getLogDeatil() {
		StringBuilder sb = new StringBuilder();
		sb.append("Instrument Id : ").append(id).append("Instrument code : ").append(this.instrumentCode);
		return sb.toString();
	}

}